home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / pucc-turnin / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-03-19  |  44.4 KB

  1. Subject:  v24i072:  Purdue tool for students to turn in work, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: e4c1bf89 f82cd38f 3ef584b8 cd1dea8f
  5.  
  6. Submitted-by: Kevin Braunsdorf <ksb@cc.purdue.edu>
  7. Posting-number: Volume 24, Issue 72
  8. Archive-name: pucc-turnin/part02
  9.  
  10. [ This has some very long lines in it; if your feed chopped them off
  11.   (shame on them!) don't worry about it -- it is only a sample.  --r$ ]
  12.  
  13. #!/bin/sh
  14. # This is part 02 of pucc-1e
  15. # ============= turnin.cf/turnin.cf ==============
  16. if test ! -d 'turnin.cf'; then
  17.     echo 'x - creating directory turnin.cf'
  18.     mkdir 'turnin.cf'
  19. fi
  20. if test -f 'turnin.cf/turnin.cf' -a X"$1" != X"-c"; then
  21.     echo 'x - skipping turnin.cf/turnin.cf (File already exists)'
  22. else
  23. echo 'x - extracting turnin.cf/turnin.cf (Text)'
  24. sed 's/^X//' << 'Purdue' > 'turnin.cf/turnin.cf' &&
  25. # $Id: turnin.cf,v 5.19 90/09/18 15:12:38 ksb Exp $
  26. # ksb's test line
  27. test:ksb:submit:system:ALL
  28. agen231:o1v:submit:agen231:ALL
  29. agen321:agen321:submit:agen321:ALL
  30. engr115:siphon:submit:engr115:130tom,330joe
  31. engr195e:195e:submit:engr195e:wed830,wed930,wed1030,wed1130,wed1230,wed130,wed230,wed330,wed430,thu830,thu930,thu1030,thu1130,thu1230,fri830,fri930,fri1030,fri1130,fri1230,fri130,fri230
  32. cs110:cvo:submit:cs110:grades
  33. cs145:w1h:submit:cs145:830mark,1030dan,1130dan,130mark,230dan,330mark
  34. cs150:xt2:submit:cs150:tagraders,d1s1,d2s1,d2s2,d3s1,d4s1,d4s2,d5s1,d5s2,d6s1,d7s1,d7s2,d8s1,d9s1,d9s2,d10s1,d10s2,d11s1,d12s1,d12s2,d13s1,d14s1,d14s2,d15s1,d15s2,d16s1,d17s1,d17s2,d18s1,d19s1,d19s2,d20s1,d20s2,d21s1,d22s1,d22s2,d23s1,d24s1,d24s2,d25s1
  35. cs151:cs151:submit:cs151:d0s0
  36. cs180:wp4:turnin:cs180:930Buster,1030Steve,130Hiralal
  37. cs181:cs181:submit:cs181:1030rec,1130rec,130rec
  38. cs250:cs250:fall90:cs250:130,330
  39. cs251:3ax:project1:cs251:ds1,ds2
  40. cs352:cs352:submit:cs352:d1s1,d3s1
  41. cs400:cs440:submit:csusers:ALL
  42. cs404:1kz:submit:cs404:ALL
  43. 404hw:cs404:submit:cs404:ALL
  44. cs413:cs413:submit:csusers:ALL
  45. cs440:cs440:submit:csusers:930
  46. cs442:cs442:submit:csusers:830,1130
  47. cs490a:cs490a:submit:csusers:d1s1,d2s1
  48. cs502:cs502:proj:csusers:ALL
  49. cs520:cs520:submit:csusers:ALL
  50. cs536:cs536ta:submit:cs536t:ALL
  51. cs543:cs543:submit:csusers:ALL
  52. cs565:cs565:submit:csusers:ALL
  53. cs590d:wne:submit:cs590d:ALL
  54. Purdue
  55. chmod 0644 turnin.cf/turnin.cf ||
  56. echo 'restore of turnin.cf/turnin.cf failed'
  57. Wc_c="`wc -c < 'turnin.cf/turnin.cf'`"
  58. test 1386 -eq "$Wc_c" ||
  59.     echo 'turnin.cf/turnin.cf: original size 1386, current size' "$Wc_c"
  60. fi
  61. # ============= turnin.cf/turnin.cf.5l ==============
  62. if test -f 'turnin.cf/turnin.cf.5l' -a X"$1" != X"-c"; then
  63.     echo 'x - skipping turnin.cf/turnin.cf.5l (File already exists)'
  64. else
  65. echo 'x - extracting turnin.cf/turnin.cf.5l (Text)'
  66. sed 's/^X//' << 'Purdue' > 'turnin.cf/turnin.cf.5l' &&
  67. .\" 
  68. .TH TURNIN.CF 5L "PUCC"
  69. .SH NAME
  70. turnin.cf \- turnin configuration file format
  71. .SH DESCRIPTION
  72. .IR Turnin,
  73. the electronic submissions program, reads which courses are using turnin,
  74. which accounts should be sent submissions, what directory to put submitted
  75. files in for each course, as well as what group the submissions should be
  76. saved under from a database called `turnin.cf'.
  77. .PP
  78. The file turnin.cf consists of a line for each course with the following
  79. information separated by colons.  The course name, the id for the account the
  80. data should be put into, the subdirectory name in which the data should
  81. be kept, and the group which should own the files after they have been
  82. submitted, and a comma separated list of the sections for this course.
  83. .SH EXAMPLE
  84. .PP
  85. A sample turnin configuration file follows:
  86. .RS
  87. .nf
  88. agen231:j1c:submit:agen231:only
  89. cs180:tt2:turnin:cs180adm:830Bob,930Allan,1030Beth,1230Raghu,330Matt
  90. cs181:lmt:submit:cs181:1030,1130,130
  91. cs190k:hpv:submit:cs190k:div1,div2,div3,div4
  92. cs250:nru:submit:cs250:d1s1,d1s2
  93. cs251:nnm:submit:cs251:Beaven,Mathur
  94. cs404:olk:submit:cs404:lab
  95. cs414:gk3:submit:csusers:mav,lian,jxy
  96. cs536:cs536ta:submit:cs536t:d1s1,d1s2
  97. eng115:m2n:submit:eng115:130,230
  98. test:ksb:submit:system:one,two
  99. .fi
  100. .RE
  101. .SH BUGS
  102. The superuser must update this file by hand.
  103. .SH "SEE ALSO"
  104. turnin(1L), project(1L), turnin(5L), tar(1)
  105. Purdue
  106. chmod 0444 turnin.cf/turnin.cf.5l ||
  107. echo 'restore of turnin.cf/turnin.cf.5l failed'
  108. Wc_c="`wc -c < 'turnin.cf/turnin.cf.5l'`"
  109. test 1361 -eq "$Wc_c" ||
  110.     echo 'turnin.cf/turnin.cf.5l: original size 1361, current size' "$Wc_c"
  111. fi
  112. # ============= project/install ==============
  113. if test ! -d 'project'; then
  114.     echo 'x - creating directory project'
  115.     mkdir 'project'
  116. fi
  117. if test -f 'project/install' -a X"$1" != X"-c"; then
  118.     echo 'x - skipping project/install (File already exists)'
  119. else
  120. echo 'x - extracting project/install (Text)'
  121. sed 's/^X//' << 'Purdue' > 'project/install' &&
  122. $ project -i
  123. project: initialize user tst for a course
  124. X
  125. Project allows other users to put files in your account.
  126. If you do not know what you are doing, stop now.
  127. Send mail to enroll-info if you have questions or need help.
  128. X
  129. Are you sure you want to do this? [ny] y
  130. X
  131. Have you ever used project to administer electronic submissions before? [ny] y
  132. X
  133. A long name for a course might be something like 
  134. X        Programming in Mud
  135. X
  136. What is the long name of this course? This is a test
  137. X
  138. A short name for a course might be something like 
  139. X        cs200
  140. X
  141. What is the short name of this course? test
  142. X
  143. All submitted files will be under a special subdirectory in your account.
  144. This directory will be world readable.
  145. What name would you give the submission directory? [submit] 
  146. X
  147. The submitted files will not be group readable, but should have an
  148. appropriate group none the less.  For most people the default is fine.
  149. X
  150. Which group should the submitted files be in ? [staff] system
  151. X
  152. Division/section identifiers separate large classes into
  153. many smaller parts for grading.
  154. Examples might be
  155. X        morning
  156. X        afternoon
  157. Or:
  158. X        d1s1
  159. X        d2s1
  160. X
  161. Enter the divisions/sections of your course one per line.
  162. Use a dot (`.') on a line by itself to stop.
  163. div/section [d1s1] > one
  164. div/section [d1s2] > two
  165. div/section [d1s3] > .
  166. X
  167. Lastly, if you would like to be notified by phone when this is done
  168. Please enter a phone number now: [No, Thanks] 
  169. X
  170. Mail has been sent to a superuser to finish the configuration.
  171. You will be contacted via email or telephone when your account
  172. is ready for use.
  173. Purdue
  174. chmod 0444 project/install ||
  175. echo 'restore of project/install failed'
  176. Wc_c="`wc -c < 'project/install'`"
  177. test 1575 -eq "$Wc_c" ||
  178.     echo 'project/install: original size 1575, current size' "$Wc_c"
  179. fi
  180. # ============= project/Makefile ==============
  181. if test -f 'project/Makefile' -a X"$1" != X"-c"; then
  182.     echo 'x - skipping project/Makefile (File already exists)'
  183. else
  184. echo 'x - extracting project/Makefile (Text)'
  185. sed 's/^X//' << 'Purdue' > 'project/Makefile' &&
  186. #    $Id: Makefile,v 4.5 90/10/07 12:55:22 ksb Exp $
  187. #
  188. #    Makefile for project
  189. #
  190. # if you do nat have strcasecmp in libc get it and add it to SRC and OBJ
  191. # (Berkeley has a free one, mkcat uses that one)
  192. X
  193. PROG=    project
  194. BIN=    ${DESTDIR}/usr/local/bin
  195. X
  196. L=../libopt
  197. #L=/usr/include/local
  198. I=/usr/include
  199. S=/usr/include/sys
  200. P=
  201. X
  202. INCLUDE= -I$L
  203. DEBUG=    -O
  204. CDEFS=  
  205. CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
  206. X
  207. HDR=    machine.h
  208. SRC=    project.c
  209. OBJ=    project.o
  210. #SRC=    project.c strcasecmp.c
  211. #OBJ=    project.o strcasecmp.o
  212. OTHER=    
  213. MAN=    project.1l
  214. SOURCE=    Makefile ${HDR} ${SRC} ${MAN} ${OTHER}
  215. X
  216. all: ${PROG}
  217. X
  218. ${PROG}:$P ${OBJ}
  219. #    ${CC} -o $@ ${CFLAGS} ${OBJ} -lopt
  220. #    ${CC} -o $@ ${CFLAGS} ${OBJ} -L /usr/local/lib -lopt
  221. X    ${CC} -o $@ ${CFLAGS} ${OBJ} ../libopt/libopt.a
  222. X
  223. clean: FRC
  224. X    rm -f Makefile.bak ${PROG} *.o a.out core errs tags
  225. X
  226. depend: ${HDR} ${SRC} FRC
  227. X    maketd ${CDEFS} ${INCLUDE} ${SRC}
  228. X
  229. install: all FRC
  230. X    install -cs ${PROG} ${BIN}/${PROG}
  231. X
  232. lint: ${HDR} ${SRC} FRC
  233. X    lint -h ${CDEFS} ${INCLUDE} ${SRC}
  234. X
  235. mkcat: ${MAN}
  236. X    mkcat ${MAN}
  237. X
  238. print: source FRC
  239. X    lpr -J'${PROG} source' ${SOURCE}
  240. X
  241. source: ${SOURCE}
  242. X
  243. spotless: clean
  244. X    rcsclean ${SOURCE}
  245. X
  246. tags: ${HDR} ${SRC}
  247. X    ctags -t ${HDR} ${SRC}
  248. X
  249. ${SOURCE}:
  250. X    co -q $@
  251. X
  252. FRC:
  253. X
  254. # DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
  255. X
  256. project.o: machine.h project.c
  257. X
  258. # *** Do not add anything here - It will go away. ***
  259. Purdue
  260. chmod 0644 project/Makefile ||
  261. echo 'restore of project/Makefile failed'
  262. Wc_c="`wc -c < 'project/Makefile'`"
  263. test 1326 -eq "$Wc_c" ||
  264.     echo 'project/Makefile: original size 1326, current size' "$Wc_c"
  265. fi
  266. # ============= turnin.cf/Makefile ==============
  267. if test -f 'turnin.cf/Makefile' -a X"$1" != X"-c"; then
  268.     echo 'x - skipping turnin.cf/Makefile (File already exists)'
  269. else
  270. echo 'x - extracting turnin.cf/Makefile (Text)'
  271. sed 's/^X//' << 'Purdue' > 'turnin.cf/Makefile' &&
  272. #    $Id: Makefile,v 4.1 90/11/28 12:42:14 ksb Exp $
  273. #
  274. #    Makefile for turnin.cf
  275. #
  276. X
  277. PROG=    turnin.cf
  278. LIB=    ${DESTDIR}/usr/local/lib
  279. X
  280. SRCl=    turnin.cf
  281. SRCs=    
  282. MAN=    turnin.5l turnin.cf.5l
  283. OTHER=    Distfile
  284. SOURCE=    Makefile ${SRCl} ${SRCs} ${MAN} ${OTHER}
  285. X
  286. all: ${SRCl} ${PROG}
  287. X
  288. clean: FRC
  289. X    rm -f Makefile.bak *.o a.out core errs tags
  290. X
  291. deinstall: ${MAN}
  292. X    install -R ${LIB}/${PROG}
  293. X    mkcat -D ${MAN}
  294. X
  295. depend: FRC
  296. X
  297. install: all FRC
  298. X    install -cm 644 ${SRCl} ${LIB}
  299. X    distrib -a Distfile
  300. X
  301. lint: FRC
  302. X
  303. mkcat: ${MAN}
  304. X    mkcat ${MAN}
  305. X
  306. print: source FRC
  307. X    lpr -J'${PROG} source' ${SOURCE}
  308. X
  309. source: ${SOURCE}
  310. X
  311. spotless: clean
  312. X    rcsclean ${SOURCE}
  313. X
  314. tags: FRC
  315. X
  316. ${SOURCE}:
  317. X    co -q $@
  318. X
  319. FRC:
  320. X
  321. # DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
  322. X
  323. # *** Do not add anything here - It will go away. ***
  324. Purdue
  325. chmod 0644 turnin.cf/Makefile ||
  326. echo 'restore of turnin.cf/Makefile failed'
  327. Wc_c="`wc -c < 'turnin.cf/Makefile'`"
  328. test 767 -eq "$Wc_c" ||
  329.     echo 'turnin.cf/Makefile: original size 767, current size' "$Wc_c"
  330. fi
  331. # ============= turnin.cf/ckcf.sh ==============
  332. if test -f 'turnin.cf/ckcf.sh' -a X"$1" != X"-c"; then
  333.     echo 'x - skipping turnin.cf/ckcf.sh (File already exists)'
  334. else
  335. echo 'x - extracting turnin.cf/ckcf.sh (Text)'
  336. sed 's/^X//' << 'Purdue' > 'turnin.cf/ckcf.sh' &&
  337. #!/bin/sh
  338. X
  339. BASE=${1-turnin.cf}
  340. X
  341. grep -v '#' < $BASE | awk -F: '{ print $4 }' |
  342. while read group
  343. do
  344. X    grep "^$group:" /etc/group >/dev/null && continue
  345. X    echo "$0: $BASE: $group: no such group"
  346. done
  347. X
  348. grep -v '#' < $BASE | awk -F: '{ print $2 }' |
  349. while read user
  350. do
  351. X    grep "^$user:" /etc/passwd >/dev/null && continue
  352. X    echo "$0: $BASE: $user: no such user"
  353. done
  354. X
  355. Xexit 0
  356. Purdue
  357. chmod 0644 turnin.cf/ckcf.sh ||
  358. echo 'restore of turnin.cf/ckcf.sh failed'
  359. Wc_c="`wc -c < 'turnin.cf/ckcf.sh'`"
  360. test 366 -eq "$Wc_c" ||
  361.     echo 'turnin.cf/ckcf.sh: original size 366, current size' "$Wc_c"
  362. fi
  363. # ============= turnin.cf/Distfile ==============
  364. if test -f 'turnin.cf/Distfile' -a X"$1" != X"-c"; then
  365.     echo 'x - skipping turnin.cf/Distfile (File already exists)'
  366. else
  367. echo 'x - extracting turnin.cf/Distfile (Text)'
  368. sed 's/^X//' << 'Purdue' > 'turnin.cf/Distfile' &&
  369. #
  370. # $Header: /usr/msrc/vax/local/lib/turnin.cf/RCS/Distfile,v 4.0 90/01/13 12:02:14 ksb Exp $
  371. #
  372. X
  373. ( /usr/local/lib/turnin.cf ) -> ( HOST )
  374. X    install ;
  375. Purdue
  376. chmod 0444 turnin.cf/Distfile ||
  377. echo 'restore of turnin.cf/Distfile failed'
  378. Wc_c="`wc -c < 'turnin.cf/Distfile'`"
  379. test 149 -eq "$Wc_c" ||
  380.     echo 'turnin.cf/Distfile: original size 149, current size' "$Wc_c"
  381. fi
  382. # ============= project/project.c ==============
  383. if test -f 'project/project.c' -a X"$1" != X"-c"; then
  384.     echo 'x - skipping project/project.c (File already exists)'
  385. else
  386. echo 'x - extracting project/project.c (Text)'
  387. sed 's/^X//' << 'Purdue' > 'project/project.c' &&
  388. /*
  389. X * project -- reads the turnin database to determin what directory    (ksb)
  390. X * it should build a turnin(1l) directory tree for the given course
  391. X * in.  Then reads a local database for a list of dXsY directories
  392. X * to build.
  393. X *
  394. X *    project [-dehiorvV] [-c course] [-G cmd] [-g cmd] [number|name]
  395. X *
  396. X * $Compile: ${cc-cc} ${cc_debug--O} -I/usr/include/local %f -o %F -lopt
  397. X */
  398. #include <sys/types.h>
  399. #include <sys/stat.h>
  400. #include <sys/file.h>
  401. #include <sys/param.h>
  402. #ifdef pdp11
  403. #include <ndir.h>
  404. #else /* VAX */
  405. #include <sys/dir.h>
  406. #include <sys/time.h>
  407. #include <sys/resource.h>
  408. #endif
  409. #include <pwd.h>
  410. #include <grp.h>
  411. #include <stdio.h>
  412. #include <ctype.h>
  413. #include <errno.h>
  414. extern int errno;
  415. extern char *sys_errlist[];
  416. #define strerror(Me)    (sys_errlist[Me])
  417. extern int pclose(), fclose();
  418. X
  419. #include "getopt.h"
  420. #include "machine.h"
  421. X
  422. #if HAVE_STRINGS
  423. #include <strings.h>
  424. #else
  425. #include <string.h>
  426. #endif
  427. X
  428. #if USE_LOCKF
  429. #include <unistd.h>
  430. #endif
  431. X
  432. extern FILE *popen();
  433. extern char *malloc(), *strchr(), *strrchr();
  434. #define strsave(Mpch) strcpy(malloc(strlen(Mpch)+1), Mpch)
  435. X
  436. static char RCSId[] =
  437. X    "$Id: project.c,v 4.9 90/09/04 08:33:35 ksb Exp $";
  438. X
  439. typedef enum {
  440. X    ON,
  441. X    OFF,
  442. X    DELETE
  443. } STATUS;
  444. X
  445. static STATUS Projstatus[MAXPROJECTS];
  446. X
  447. typedef enum {
  448. X    DISABLE,        /* submissions off            */
  449. X    ENABLE,            /* submissions on for project        */
  450. X    HELP,            /* need help                */
  451. X    INITIALIZE,        /* set up the intructors account    */
  452. X    OUTPUT,            /* display status            */
  453. X    QUIT,            /* stop using project, request del    */
  454. X    REMOVE,            /* delete submissions for proj        */
  455. X    GRADE,            /* scan directories for tar file    */
  456. X    LATE,            /* enable late submissions        */
  457. X    VERSION,        /* show version of project running    */
  458. X    UNKNOWN            /* we were not told            */
  459. } WHAT;
  460. X
  461. static WHAT What;        /* what am I doing            */
  462. X
  463. static int
  464. X    fExec = 1,        /* do commands                */
  465. X    fVerbose = 0,        /* print shell cmds            */
  466. X    iProjnum = -1,        /* default project            */
  467. X    iProjcount = 0;        /* number of projects            */
  468. X
  469. static struct passwd
  470. X    *ppwMe;            /* more deatails about the owner    */
  471. X
  472. static char
  473. X    acMd[MAXDIVSEC+1],    /*    %d    div/sec as in (dXsX)    */
  474. X    acMp[MAXPROJNAME+1],    /*    %p    the project number    */
  475. X    acMu[MAXLOGINNAME+1],    /*    %u    uid of student        */
  476. X    aacProjnames[MAXPROJNAME+1][MAXPROJECTS],
  477. X                /* names of projects            */
  478. X    *progname =        /* name we run under            */
  479. X        RCSId,
  480. X    *pcSum,            /* command per division            */
  481. X    *pcCmd;            /* command to unpack            */
  482. X
  483. static char
  484. X    acLine[MAXCHARS],    /* all these point in here        */
  485. X    *pcCourse,        /* who                    */
  486. X    *pcUid,            /* who -> uid                */
  487. X    *pcDir,            /* who -> where                */
  488. X    *pcGroup,        /* who -> group                */
  489. X    *pcSections,        /* who -> sections            */
  490. X    acSubmit[] = "submit",    /* default turnin directory        */
  491. X    acLock[] = LOCKFILE,    /* keep lock a file, many projects loose*/
  492. X    acMailAddr[] = MAILTO,    /* sys admin's address            */
  493. X    acSectIgnore[] =    /* section that means ``none given''    */
  494. X        SECTIGNORE,
  495. X    acTurnbase[] =        /* data base of project co-ordinators    */
  496. X        TURNBASE,
  497. X    acDeadLetter[] =    /* maildrop for dead mail        */
  498. X        "dead.letter";
  499. X
  500. X
  501. /*
  502. X * reads a configuration file of the form:            (doc/ksb)
  503. X * course:alpha login:subdir for this course:alpha gid:sections\n
  504. X */
  505. int
  506. getcourse(pcBase)
  507. char *pcBase;
  508. {
  509. X    register FILE *fpDB;
  510. X    register char *pc;
  511. X    register int line;
  512. X    register char *pcMaybe;
  513. X    static char acError[] = "%s: %s(%d): error in data base\n";
  514. X
  515. X    if (0 == (fpDB = fopen(pcBase, "r"))) {
  516. X        fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcBase, strerror(errno));
  517. X        exit(errno);
  518. X    }
  519. X
  520. X    line = 0;
  521. X    while (NULL != fgets(acLine, MAXCHARS, fpDB)) {
  522. X        ++line;
  523. X        pcMaybe = acLine;
  524. X        while (isspace(*pcMaybe) && '\n' != *pcMaybe)
  525. X            ++pcMaybe;
  526. X        if ('#' == *pcMaybe || '\n' == *pcMaybe)
  527. X            continue;
  528. X        if (NULL == (pc = strchr(acLine, SEP))) {
  529. X            fprintf(stdout, acError, progname, pcBase, line);
  530. X            exit(16);
  531. X        }
  532. X        *pc++ = '\000';
  533. X        pcUid = pc;
  534. X        if (NULL == (pc = strchr(pc, SEP))) {
  535. X            fprintf(stdout, acError, progname, pcBase, line);
  536. X            exit(17);
  537. X        }
  538. X        *pc++ = '\000';
  539. X        pcDir = pc;
  540. X        if (NULL == (pc = strchr(pc, SEP))) {
  541. X            fprintf(stdout, acError, progname, pcBase, line);
  542. X            exit(18);
  543. X        }
  544. X        *pc++ = '\000';
  545. X        pcGroup = pc;
  546. X        if (NULL == (pc = strchr(pc, SEP))) {
  547. X            fprintf(stdout, acError, progname, pcBase, line);
  548. X            exit(19);
  549. X        }
  550. X        *pc++ = '\000';
  551. X        pcSections = pc;
  552. X        if (NULL != (pc = strchr(pc, '\n'))) {
  553. X            *pc = '\000';
  554. X        }
  555. X        if ((char *)0 != pcCourse && 0 == strcmp(pcCourse, pcMaybe)) {
  556. X            return 1;
  557. X        }
  558. X        if ((char *)0 == pcCourse && 0 == strcmp(pcUid, ppwMe->pw_name)) {
  559. X            pcCourse = pcMaybe;
  560. X            return 1;
  561. X        }
  562. X    }
  563. X    return 0;
  564. }
  565. X
  566. /*
  567. X * get the cmdline options
  568. X */
  569. static void
  570. options(argc, argv)
  571. register int argc;
  572. register char **argv;
  573. {
  574. X    static char acOpts[] = "c:dehinorvVlqg:G:";
  575. X    static char acTwo[] = "%s: %s: more than one task given\n";
  576. X    register int n;
  577. X
  578. X    What = UNKNOWN;
  579. X    while (EOF != (n = getopt(argc, argv, acOpts))) {
  580. X        switch (n) {
  581. X        case 'c':
  582. X            pcCourse = optarg;
  583. X            break;
  584. X        case 'd':
  585. X            if (UNKNOWN != What) {
  586. X                fprintf(stderr, acTwo, progname, "disable");
  587. X                exit(1);
  588. X            }
  589. X            What = DISABLE;
  590. X            break;
  591. X        case 'e':
  592. X            if (UNKNOWN != What) {
  593. X                fprintf(stderr, acTwo, progname, "enable");
  594. X                exit(1);
  595. X            }
  596. X            What = ENABLE;
  597. X            break;
  598. X        case 'G':
  599. X            if (UNKNOWN != What && GRADE != What) {
  600. X                fprintf(stderr, acTwo, progname, "grade");
  601. X                exit(1);
  602. X            }
  603. X            if ((char *)0 != pcSum) {
  604. X                fprintf(stderr, "%s: grade: two commands given for `G\'\n", progname);
  605. X                exit(1);
  606. X            }
  607. X            What = GRADE;
  608. X            pcSum = optarg;
  609. X            break;
  610. X        case 'g':
  611. X            if (UNKNOWN != What && GRADE != What) {
  612. X                fprintf(stderr, acTwo, progname, "grade");
  613. X                exit(1);
  614. X            }
  615. X            if ((char *)0 != pcCmd) {
  616. X                fprintf(stderr, "%s: grade: two commands given for `g\'\n", progname);
  617. X                exit(1);
  618. X            }
  619. X            What = GRADE;
  620. X            pcCmd = optarg;
  621. X            break;
  622. X        case 'l':
  623. X            if (UNKNOWN != What) {
  624. X                fprintf(stderr, acTwo, progname, "late");
  625. X                exit(1);
  626. X            }
  627. X            What = LATE;
  628. X            break;
  629. X        case 'h':
  630. X            if (UNKNOWN != What) {
  631. X                fprintf(stderr, acTwo, progname, "help");
  632. X                exit(1);
  633. X            }
  634. X            What = HELP;
  635. X            break;
  636. X        case 'i':
  637. X            if (UNKNOWN != What) {
  638. X                fprintf(stderr, acTwo, progname, "initialize");
  639. X                exit(1);
  640. X            }
  641. X            What = INITIALIZE;
  642. X            break;
  643. X        case 'o':
  644. X            if (UNKNOWN != What) {
  645. X                fprintf(stderr, acTwo, progname, "output");
  646. X                exit(1);
  647. X            }
  648. X            What = OUTPUT;
  649. X            break;
  650. X        case 'n':
  651. X            fExec = 0;
  652. X            break;
  653. X        case 'V':
  654. X            if (UNKNOWN != What) {
  655. X                fprintf(stderr, acTwo, progname, "version");
  656. X                exit(1);
  657. X            }
  658. X            What = VERSION;
  659. X            break;
  660. X        case 'v':
  661. X            fVerbose = 1;
  662. X            break;
  663. X        case 'q':
  664. X            if (UNKNOWN != What) {
  665. X                fprintf(stderr, acTwo, progname, "quit");
  666. X                exit(1);
  667. X            }
  668. X            What = QUIT;
  669. X            break;
  670. X        case 'r':
  671. X            if (UNKNOWN != What) {
  672. X                fprintf(stderr, acTwo, progname, "remove");
  673. X                exit(1);
  674. X            }
  675. X            What = REMOVE;
  676. X            break;
  677. X        default:
  678. X            break;
  679. X        }
  680. X    }
  681. }
  682. X
  683. /*
  684. X * remove the trailing newline from a fgets'd input line        (ray)
  685. X */
  686. static void
  687. fixup(string)
  688. register char *string;
  689. {
  690. X    char *newline;
  691. X
  692. X    if (NULL != (newline = strchr(string, '\n'))) {
  693. X        *newline = '\000';
  694. X    }
  695. }
  696. X
  697. static char acProjlist[] =        /* path to project list        */
  698. X    PROJLIST;
  699. X
  700. /*
  701. X * check for illegal chars in project name                (ksb)
  702. X */
  703. void
  704. CheckChars(pcFrom, pcProj)
  705. char *pcFrom, *pcProj;
  706. {
  707. X    if ('\000' == *pcProj) {
  708. X        fprintf(stderr, "%s: empty project name given %s\n", progname, pcFrom);
  709. X        exit(8);
  710. X    }
  711. X    do {
  712. X        switch (*pcProj) {
  713. X        case '/':
  714. X        case '.':
  715. X            fprintf(stderr, "%s: project name given %s cannot contain `%c\'.\n", progname, pcFrom, *pcProj);
  716. X            exit(8);
  717. X        default:
  718. X            break;
  719. X        }
  720. X    } while ('\000' != *++pcProj);
  721. }
  722. X
  723. X
  724. /*
  725. X * open projlist & read it                        (ksb)
  726. X */
  727. int
  728. getprojects()
  729. {
  730. X    register FILE *fp;
  731. X    auto int status;
  732. X    auto int proj;
  733. X
  734. X    if (NULL == (fp = fopen(acProjlist, "r"))) {
  735. X        if (fExec) {
  736. X            if (NULL == (fp = fopen(acProjlist, "w"))) {
  737. X                fprintf(stderr, "%s: fopen: %s: %s\n", progname, acProjlist, strerror(errno));
  738. X                exit(errno);
  739. X            }
  740. X            fclose(fp);
  741. X        }
  742. X        iProjcount = 0;
  743. X        return;
  744. X    }
  745. X    proj = 0;
  746. X    while (EOF != (status = getc(fp))) {
  747. X        switch(status) {
  748. X        case '-':
  749. X            fgets(aacProjnames[proj], MAXCHARS, fp);
  750. X            Projstatus[proj] = OFF;
  751. X            break;
  752. X        case '+':
  753. X            fgets(aacProjnames[proj], MAXCHARS, fp);
  754. X            Projstatus[proj] = ON;
  755. X            break;
  756. X        case '=':
  757. X            fgets(aacProjnames[proj], MAXCHARS, fp);
  758. X            Projstatus[proj] = ON;
  759. X            iProjnum = proj;
  760. X            break;
  761. X        default:
  762. X            fprintf(stderr, "%s: `%s\' is hosed\n", progname, acProjlist);
  763. X            exit(20);
  764. X            break;
  765. X        }
  766. X        fixup(aacProjnames[proj]);
  767. X        CheckChars("in `Projlist\'", aacProjnames[proj]);
  768. X        proj++;
  769. X    }
  770. X    iProjcount = proj;
  771. X    fclose(fp);
  772. }
  773. X
  774. /*
  775. X * find a project in the in-core database                (ksb)
  776. X */
  777. int
  778. search(name)
  779. register char *name;
  780. {
  781. X    int i;
  782. X
  783. X    for (i = 0; i < iProjcount; ++i) {
  784. X        if (0 == strcasecmp(name, aacProjnames[i])) {
  785. X            return i;
  786. X        }
  787. X    }
  788. X
  789. X    ++iProjcount;
  790. X    Projstatus[i] = ON;
  791. X    strcpy(aacProjnames[i], name);
  792. X    return i;
  793. }
  794. X
  795. /*
  796. X * update the PROJLIST file                        (doc/ksb)
  797. X */
  798. static void
  799. newprojects(fWarn)
  800. int fWarn;    /* warn of no default project. */
  801. {
  802. X    register FILE *fp;
  803. X    register int projout;
  804. X    register int flag1 = 0;
  805. X    register int flag2 = 0;
  806. X
  807. X    if (fExec) {
  808. X        if (NULL == (fp = fopen(acProjlist, "w"))) {
  809. X            fprintf(stderr, "%s: fopen: %s: %s\n", progname, acProjlist, strerror(errno));
  810. X            exit(1);
  811. X        }
  812. X    }
  813. X
  814. X    for (projout = 0; projout < iProjcount; projout++) {
  815. X        if (Projstatus[projout] != DELETE) {
  816. X            if (fExec) {
  817. X                fprintf(fp, "%c%s\n",
  818. X                    Projstatus[projout] == OFF ? '-' :
  819. X                    iProjnum == projout ? '=' : '+',
  820. X                    aacProjnames[projout]);
  821. X            }
  822. X            if (fVerbose) {
  823. X                fprintf(stdout, "echo %c%s %s %s\n",
  824. X                    Projstatus[projout] == OFF ? '-' :
  825. X                    iProjnum == projout ? '=' : '+',
  826. X                    aacProjnames[projout],
  827. X                    flag2 == 0 ? ">" : ">>",
  828. X                    acProjlist);
  829. X                flag2 = 1;
  830. X            }
  831. X            if (projout == iProjnum && Projstatus[projout] == ON) {
  832. X                flag1 = 1;
  833. X            }
  834. X        }
  835. X    }
  836. X    if (fExec) {
  837. X        fclose(fp);
  838. X    }
  839. X    if (flag1 == 0 && fWarn) {
  840. X        fprintf(stderr, "%s: no default project\n", progname);
  841. X    }
  842. }
  843. X
  844. /*
  845. X * chdir to the argument, create it if you can't find it        (ksb)
  846. X */
  847. static void
  848. ceedee(pcMove)
  849. char *pcMove;
  850. {
  851. X    if (0 != chdir(pcMove)) {
  852. X        if (fExec) {
  853. X            if (0 != mkdir(pcMove, 0755) || 0 != chdir(pcMove)) {
  854. X                fprintf(stderr, "%s: chdir: %s: %s\n", progname, pcMove, strerror(errno));
  855. X                exit(1);
  856. X            }
  857. X        }
  858. X        if (fVerbose) {
  859. X            fprintf(stdout, "mkdir %s\n", pcMove);
  860. X        }
  861. X    }
  862. X    if (fVerbose) {
  863. X        fprintf(stdout, "cd %s\n", pcMove);
  864. X    }
  865. }
  866. X
  867. /*
  868. X * you don't want to look at thew next four blocks            (ksb)
  869. X */
  870. static char acComma[] = ",.";
  871. static char *_pc = acComma+1;
  872. X
  873. static void
  874. trav_init()
  875. {
  876. X    _pc = pcSections;
  877. }
  878. X
  879. static int
  880. traverse(pcBuf)
  881. char *pcBuf;
  882. {
  883. X    extern char *strchr();
  884. X    register char *p;
  885. X
  886. X    if (_pc == acComma+1)
  887. X        return 0;
  888. X
  889. X    if ((char *)0 == (p = strchr(_pc, ','))) {
  890. X        p = acComma;
  891. X    }
  892. X    *p = '\000';
  893. X    strcpy(pcBuf, _pc);
  894. X    *p = ',';
  895. X    _pc = p+1;
  896. X
  897. X    return 1;
  898. }
  899. X
  900. /*
  901. X * close off traverse
  902. X */
  903. static void
  904. travisty()
  905. {
  906. X    ;
  907. }
  908. X
  909. /*
  910. X * get the file lock for us                        (ksb)
  911. X */
  912. int
  913. OpenLock()
  914. {
  915. X    auto int fdLock;
  916. X
  917. X    if (-1 == (fdLock = open(acLock, O_RDWR|O_CREAT, 0600))) {
  918. X        fprintf(stderr, "%s: open: %s: %s\n", progname, acLock, strerror(errno));
  919. X        exit(1);
  920. X    }
  921. X
  922. #if USE_LOCKF
  923. X    if (lockf(fdLock, F_TLOCK, 0) == -1) {
  924. X        if (errno == EAGAIN || errno == EACCES) {
  925. X            fprintf(stderr, "%s: waiting for lock\n", progname);
  926. X            if (lockf(fdLock, F_LOCK, 0) == -1) {
  927. X                goto bad_lock;
  928. X            }
  929. X            fprintf(stderr, "%s: got lock\n", progname);
  930. X        } else {
  931. X    bad_lock:
  932. X            fprintf(stderr, "%s: lockf: %s\n", progname, strerror(errno));
  933. X            exit(2);
  934. X        }
  935. X    }
  936. #else
  937. X    if (-1 == flock(fdLock, LOCK_NB|LOCK_EX)) {
  938. X        if (EWOULDBLOCK == errno) {
  939. X            fprintf(stderr, "%s: waiting for lock\n", progname);
  940. X            if (-1 == flock(fdLock, LOCK_EX)) {
  941. X                goto bad_lock;
  942. X            }
  943. X            fprintf(stderr, "%s: got lock\n", progname);
  944. X        } else {
  945. X    bad_lock:
  946. X            fprintf(stderr, "%s: flock: %s\n", progname, strerror(errno));
  947. X            exit(1);
  948. X        }
  949. X    }
  950. #endif
  951. X
  952. #if defined(F_SETFD)
  953. X    if (-1 == fcntl(fdLock, F_SETFD, 1)) {
  954. X        fprintf(stderr, "%s: fcntl: %s (ignored)\n", progname, strerror(errno));
  955. X    }
  956. #endif
  957. X    return fdLock;
  958. }
  959. X
  960. /*
  961. X * make the project tree (if it doesn't exist)                (ksb)
  962. X */
  963. static void
  964. Make(pcProj)
  965. char *pcProj;
  966. {
  967. X    auto char acDivSec[MAXDIVSEC];
  968. X
  969. X    ceedee(pcProj);
  970. X    if (0 != strcmp(acSectIgnore, pcSections)) {
  971. X        trav_init();
  972. X        while (traverse(acDivSec)) {
  973. X            if (fVerbose) {
  974. X                fprintf(stdout, "mkdir %s\n", acDivSec);
  975. X            }
  976. X            if (!fExec) {
  977. X                continue;
  978. X            }
  979. X            if (0 != mkdir(acDivSec, 0755) && EEXIST != errno) {
  980. X                fprintf(stderr, "%s: mkdir: %s\n", progname, strerror(errno));
  981. X                exit(2);
  982. X            }
  983. X        }
  984. X        travisty();
  985. X    }
  986. X    ceedee("..");
  987. }
  988. X
  989. /*
  990. X * fork off a UNIX rm to recursively remove unloved files        (ksb)
  991. X */
  992. static void
  993. rm(pcFile)
  994. char *pcFile;
  995. {
  996. X    if (fVerbose) {
  997. X        fprintf(stdout, "rm -rf %s\n", pcFile);
  998. X    }
  999. X    if (fExec) {
  1000. X        if (0 == fork()) {
  1001. X            execl("/bin/rm", "rm", "-rf", pcFile, 0);
  1002. X            fprintf(stderr, "%s: execl: /bin/rm: %s\n", progname, strerror(errno));
  1003. X            exit(1);
  1004. X        }
  1005. X        wait(0);
  1006. X    }
  1007. }
  1008. X
  1009. /*
  1010. X * remove the dir struct for a project with some rm's            (ksb)
  1011. X */
  1012. static void
  1013. Remove(pcProj)
  1014. char *pcProj;
  1015. {
  1016. X    auto char acDivSec[MAXDIVSEC];
  1017. X
  1018. X    if (0 != chdir(pcProj)) {        /* no exist, don't make */
  1019. X        return;
  1020. X    }
  1021. X    chdir("..");
  1022. X    ceedee(pcProj);        /* for verbose mode    */
  1023. X    if (0 != strcmp(acSectIgnore, pcSections)) {
  1024. X        trav_init();
  1025. X        while (traverse(acDivSec)) {
  1026. X            rm(acDivSec);
  1027. X        }
  1028. X        travisty();
  1029. X    }
  1030. X    ceedee("..");
  1031. X    rm(pcProj);
  1032. }
  1033. X
  1034. /*
  1035. X * like strcat, but return value is end of string            (doc)
  1036. X */
  1037. static char *
  1038. stradd(pcTo, pcFrom)
  1039. register char *pcFrom, *pcTo;
  1040. {
  1041. X    while (*pcTo = *pcFrom++)
  1042. X        ++pcTo;
  1043. X    return pcTo;
  1044. }
  1045. X
  1046. /*
  1047. X * using the global state, produce a shell cammand an system it off    (ksb)
  1048. X *
  1049. X * escapse in command:
  1050. X *    %u    uid of student
  1051. X *    %d    division/section is (dXsX)
  1052. X *    %p    the project number
  1053. X *    %t    submissions directory
  1054. X *    %h    home of grader
  1055. X *    %s    full path %h/%t/%p/%d/%u
  1056. X *    %%    a %
  1057. X */
  1058. static void
  1059. grade(pcFrom)
  1060. register char *pcFrom;
  1061. {
  1062. X    static char *pcExec = (char *)0;
  1063. X    register char *pcTo;
  1064. X
  1065. X    if ((char *)0 == pcExec) {
  1066. X        pcExec = malloc(NCARGS);
  1067. X        if ((char *)0 == pcExec) {
  1068. X            fprintf(stderr, "%s: out of memory\n", progname);
  1069. X            exit(errno);
  1070. X        }
  1071. X    }
  1072. X    pcTo = pcExec;
  1073. X    while ('\000' != pcFrom[0]) {
  1074. X        if ('%' == pcFrom[0]) {
  1075. X            ++pcFrom;
  1076. X            switch (*pcFrom++) {
  1077. X            case '%':
  1078. X                *pcTo++ = '%';
  1079. X                continue;
  1080. X            case 'u':
  1081. X                pcTo = stradd(pcTo, acMu);
  1082. X                break;
  1083. X            case 'd':
  1084. X                pcTo = stradd(pcTo, acMd);
  1085. X                break;
  1086. X            case 'p':
  1087. X                pcTo = stradd(pcTo, acMp);
  1088. X                break;
  1089. X            case 't':
  1090. X                pcTo = stradd(pcTo, pcDir);
  1091. X                break;
  1092. X            case 'h':
  1093. X                pcTo = stradd(pcTo, ppwMe->pw_dir);
  1094. X                break;
  1095. X            case 's':
  1096. X                pcTo = stradd(pcTo, ppwMe->pw_dir);
  1097. X                *pcTo++ = '/';
  1098. X                pcTo = stradd(pcTo, pcDir);
  1099. X                *pcTo++ = '/';
  1100. X                pcTo = stradd(pcTo, acMp);
  1101. X                *pcTo++ = '/';
  1102. X                pcTo = stradd(pcTo, acMd);
  1103. X                *pcTo++ = '/';
  1104. X                pcTo = stradd(pcTo, acMu);
  1105. X                break;
  1106. X            case '\000':
  1107. X                fprintf(stderr, "%s: grade: command ends in %%?", progname);
  1108. X                exit(1);
  1109. X            default:
  1110. X                fprintf(stderr, "%s: grade: `%c\' unknown %% escape\n", progname, pcFrom[-1]);
  1111. X                exit(1);
  1112. X            }
  1113. X        } else {
  1114. X            *pcTo++ = *pcFrom++;
  1115. X        }
  1116. X    }
  1117. X    *pcTo = '\000';
  1118. X
  1119. X    if (fVerbose) {
  1120. X        printf("%s\n", pcExec);
  1121. X    }
  1122. X
  1123. X    if (fExec) {
  1124. X        system(pcExec);
  1125. X    }
  1126. }
  1127. X
  1128. /* scan a directory for tar files to grade                (ksb)
  1129. X */
  1130. scandiv(student)
  1131. DIR *student;
  1132. {
  1133. X    register struct direct *dpstudent;
  1134. X    register char *pcDot;
  1135. X
  1136. X    while (NULL != (dpstudent = readdir(student))) {
  1137. X        if ('.' == dpstudent->d_name[0])    /* skip . */
  1138. X            continue;
  1139. X        strcpy(acMu, dpstudent->d_name);
  1140. X        if ((char *)0 == pcCmd) {
  1141. X            /* do nothing */;
  1142. X        } else if ((char *)0 != (pcDot = strrchr(acMu, '.')) && 'Z' == pcDot[1] && '\000' == pcDot[2]) {
  1143. X            *pcDot = '\000';
  1144. X            grade("zcat %u.Z >%u");
  1145. X            grade(pcCmd);
  1146. X            grade("rm -f %u");
  1147. X            *pcDot = '.';
  1148. X        } else {
  1149. X            grade(pcCmd);
  1150. X        }
  1151. X    }
  1152. X    closedir(student);
  1153. X    if ((char *)0 != pcSum) {
  1154. X        strcpy(acMu, "*");
  1155. X        grade(pcSum);
  1156. X    }
  1157. }
  1158. X
  1159. /*
  1160. X * scan the project directory and system off the commands        (ksb)
  1161. X * (with grade())
  1162. X */
  1163. void
  1164. scan()
  1165. {
  1166. X    register struct direct *dp;
  1167. X    register DIR *proj, *student;
  1168. X
  1169. X    ceedee(acMp);
  1170. X    proj = opendir(".");
  1171. X    if (0 == strcmp(pcSections, acSectIgnore)) {
  1172. X        (void)strcpy(acMd, ".");
  1173. X        scandiv(proj);
  1174. X    } else {
  1175. X        while (NULL != (dp = readdir(proj))) {
  1176. X            if ('.' == dp->d_name[0]) /* dot entries skipped */
  1177. X                continue;
  1178. X            ceedee(dp->d_name);
  1179. X            (void)strcpy(acMd, dp->d_name);
  1180. X            student = opendir(".");
  1181. X            scandiv(student);
  1182. X            ceedee("..");
  1183. X        }
  1184. X        closedir(proj);
  1185. X    }
  1186. X    ceedee("..");
  1187. }
  1188. X
  1189. /*
  1190. X * get the words of wisdom from the user                (ksb)
  1191. X * strip leading white space, etc
  1192. X */
  1193. char *
  1194. GetWord(pcBuf, iLen, pcDef)
  1195. char *pcBuf, *pcDef;
  1196. int iLen;
  1197. {
  1198. X    register char *pcWhite, *pcCopy;
  1199. X    register int l;
  1200. X
  1201. X    fflush(stdout);
  1202. X    pcBuf[0] = '\n';
  1203. X    if ((char *)0 == fgets(pcBuf, iLen, stdin))
  1204. X        return (char *)0;
  1205. X    pcWhite = pcBuf;
  1206. X    while (isspace(*pcWhite) && '\n' != *pcWhite)
  1207. X        ++pcWhite;
  1208. X
  1209. X    pcCopy = pcBuf;
  1210. X    l = iLen;
  1211. X    while (l-- > 0 && '\n' != (*pcCopy = *pcWhite))
  1212. X        ++pcCopy, ++pcWhite;
  1213. X
  1214. X    if (pcCopy == pcBuf)
  1215. X        (void)strncpy(pcBuf, pcDef, iLen);
  1216. X    else
  1217. X        *pcCopy = '\000';
  1218. X    return pcBuf;
  1219. }
  1220. X
  1221. /*
  1222. X * is a name a poor name for a course or subdirectory            (ksb)
  1223. X */
  1224. int
  1225. BadName(pc)
  1226. char *pc;
  1227. {
  1228. X    if ('\000' == *pc)
  1229. X        return 1;
  1230. X    for (; '\000' != *pc; ++pc) {
  1231. X        if (!isalnum(*pc) && *pc != '-' && *pc != '_')
  1232. X            return 1;
  1233. X    }
  1234. X    return 0;
  1235. }
  1236. X
  1237. /*
  1238. X * build the project managers data structures in the file system    (ksb)
  1239. X * also mail off a request to be added to the database
  1240. X * we must be in the users home directory here!
  1241. X * (Return the locked fd that keeps other projects blocked)
  1242. X */
  1243. int
  1244. DoInit()
  1245. {
  1246. X    auto char acBuf[MAXCHARS+1], acCmd[MAXPATHLEN+300],
  1247. X        acShort[MAXCOURSENAME+1], acDir[MAXSUBDIRNAME+1],
  1248. X        acGroup[MAXGROUPNAME+1], acDefGroup[MAXGROUPNAME+1],
  1249. X        acLong[MAXLONGNAME+1],
  1250. X        acTemp[MAXDIVSEC+1], acDiv[MAXDIVSEC+1],
  1251. X        acPrevExp[MAXYESNO+1], *pcComma;
  1252. X    auto struct group *pgr;
  1253. X    auto FILE *fpMail;
  1254. X    auto int fdLock, cnt, div, sec, fProc, fFound;
  1255. X    auto struct stat stDir;
  1256. X    extern struct group *getgrgid(), *getgrnam();
  1257. X
  1258. X    setgrent();
  1259. X    if ((struct group *)0 == (pgr = getgrgid(getegid()))) {
  1260. X        fprintf(stderr, "%s: getgrgid: %d: %s\n", progname, getegid(), strerror(errno));
  1261. X        exit(1);
  1262. X    }
  1263. X    (void)strcpy(acDefGroup, pgr->gr_name);
  1264. X
  1265. X    printf("\nEnabling %s to accept electronic submissions\n", ppwMe->pw_name);
  1266. X    printf("\n\
  1267. Project allows other users to put files in your account.  Please supply\n\
  1268. the information requested below so that your account can be enabled to\n\
  1269. accept submissions from turnin(1L).  If you have questions or need help\n\
  1270. ask a general consultant or send mail to \"%s\".\n", acMailAddr);
  1271. X    printf("\n\
  1272. If you make a mistake you do not see a way to correct simply\n\
  1273. finish this run and run the program again.\n");
  1274. X
  1275. X    for (;;) {
  1276. X        printf("\nAre you sure you want to do this? [ny] ");
  1277. X        if ((char *)0 == GetWord(acBuf, MAXCHARS, "no"))
  1278. X            exit(0);
  1279. X        switch (acBuf[0]) {
  1280. X        case 'q':
  1281. X        case 'Q':
  1282. X        case 'N':
  1283. X        case 'n':
  1284. X            exit(0);
  1285. X        case 'y':
  1286. X        case 'Y':
  1287. X            break;
  1288. X        default:
  1289. X            continue;
  1290. X        }
  1291. X        break;
  1292. X    }
  1293. X
  1294. X    if (0 != stat(".", & stDir)) {
  1295. X        fprintf(stderr, "%s: stat: .: %s\n", progname, strerror(errno));
  1296. X        exit(2);
  1297. X    }
  1298. X    if ((stDir.st_mode & 0755) != 0755) {
  1299. X        printf("\nYour home directory *must* be kept world readable so that\n");
  1300. X        printf("students and consultants can use turnin -v to see if they have\n");
  1301. X        printf("submitted anything.\n");
  1302. X        if (0 != chmod(".", stDir.st_mode | 0755)) {
  1303. X            fprintf(stderr, "%s: chmod: .: %s\n", progname, strerror(errno));
  1304. X            exit(2);
  1305. X        }
  1306. X    } else {
  1307. X        printf("\nYour home directory is already world readable.  Please keep it that way\n");
  1308. X        printf("so that students and consultants can use turnin -v.\n");
  1309. X    }
  1310. X
  1311. X    printf("\nHave you ever used %s to administer electronic submissions before? [ny] ", progname);
  1312. X    if ((char *)0 == GetWord(acPrevExp, MAXYESNO, "none"))
  1313. X        exit(0);
  1314. X
  1315. X    do {
  1316. X        printf("\nA long name for a course might be something like \n\tProgramming in Mud\n");
  1317. X        printf("\nWhat is the long name of this course? ");
  1318. X        if ((char *)0 == GetWord(acLong, MAXLONGNAME, ""))
  1319. X            exit(0);
  1320. X    } while ('\000' == acLong[0]);
  1321. X
  1322. X    for (;;) {
  1323. X        do {
  1324. X            printf("\nA short name for a course might be something like \n\tcs200\n");
  1325. X            printf("\nWhat is the short name of this course [%s]? ", acDefGroup);
  1326. X
  1327. X            if ((char *)0 == GetWord(acShort, MAXCOURSENAME, acDefGroup))
  1328. X                exit(0);
  1329. X        } while ('\000' == acShort);
  1330. X        if (strlen(acShort) > MAXCOURSENAME) {
  1331. X            printf("Pick a shorter name, please.\n");
  1332. X            continue;
  1333. X        }
  1334. X        if (BadName(acShort)) {
  1335. X            printf("Course names cannot have special characters in them (except '-').\n");
  1336. X            continue;
  1337. X        }
  1338. X        break;
  1339. X    }
  1340. X
  1341. X    pcCourse = acShort;
  1342. X    pcUid = (char *)0;
  1343. X    fFound = getcourse(acTurnbase);
  1344. X    if (fFound) {
  1345. X        printf("Course `%s' already exists owner %s.%s in %s", acShort, pcUid, pcGroup, pcDir);
  1346. X        if (0 != strcmp(acSectIgnore, pcSections))
  1347. X            printf("/{%s}", pcSections);
  1348. X        printf(".\n");
  1349. X    } else {
  1350. X        pcDir = acSubmit;
  1351. X        pcGroup = acDefGroup;
  1352. X        pcSections = (char *)0;
  1353. X    }
  1354. X
  1355. X    for (;;) {
  1356. X        printf("\nAll submitted files will be under a special subdirectory in your account.\n");
  1357. X        printf("This directory will be world readable.\n");
  1358. X        printf("\nWhat do you want your submission directory named? [%s] ", pcDir);
  1359. X        if ((char *)0 == GetWord(acDir, MAXSUBDIRNAME, pcDir))
  1360. X            exit(0);
  1361. X        if (!BadName(acDir)) {
  1362. X            break;
  1363. X        }
  1364. X        printf("The directory name must be alpha-numeric.\n");
  1365. X    }
  1366. X
  1367. X    printf("\nThe submitted files will not be group readable, but should have an\n");
  1368. X    printf("appropriate group none the less.  For most people the default is fine.\n");
  1369. X    for (;;) {
  1370. X        printf("\nWhich group should the submitted files be in ? [%s] ", pcGroup);
  1371. X        if ((char *)0 == GetWord(acGroup, MAXGROUPNAME, pcGroup)) {
  1372. X            exit(0);
  1373. X        }
  1374. X        if ((struct group *)0 != (pgr = getgrnam(acGroup))) {
  1375. X            break;
  1376. X        }
  1377. X        printf("getgrname: %s: not found\n", acGroup);
  1378. X    }
  1379. X
  1380. X    ceedee(acDir);
  1381. X    fdLock = OpenLock();    /* closed by exit or caller */
  1382. X
  1383. X    sprintf(acCmd, "%s -s \"%s: request for \\`%s'\" %s", MAILX_PATH, progname, acShort, acMailAddr);
  1384. X    if (!fExec) {
  1385. X        if ((FILE *)0 == (fpMail = fopen("/dev/null", "w"))) {
  1386. X            fprintf(stderr, "%s: fopen: /dev/null: %s\n", progname, strerror(errno));
  1387. X            exit(1);
  1388. X        }
  1389. X        fProc = 0;
  1390. X    } else if ((FILE *)0 == (fpMail = popen(acCmd, "w"))) {
  1391. X        fprintf(stderr, "%s: cannot mail to (%s).\n", progname, strerror(errno));
  1392. X        if ((FILE *)0 == (fpMail = fopen(acDeadLetter, "a"))) {
  1393. X            exit(1);
  1394. X        }
  1395. X        fprintf(stderr, "%s: holding letter in %s\n", progname, acDeadLetter);
  1396. X        fProc = 0;
  1397. X    } else {
  1398. X        fProc = 1;
  1399. X    }
  1400. X    fprintf(fpMail, "Entry for `%s\' requested as follows:\n", acLong);
  1401. X    fprintf(fpMail, "\t%s%c%s%c%s%c%s", acShort, SEP, ppwMe->pw_name, SEP, acDir, SEP, acGroup);
  1402. X
  1403. X    printf("\n\
  1404. You can separate a large course into a few smaller parts for grading by\n\
  1405. assigning division/section identifiers.\n\n");
  1406. X    printf("Three common naming conventions are listed below:\n");
  1407. X    printf("\tmorning\t\tafternoon\n");
  1408. X    printf("\t930scott\t230kevin\n");
  1409. X    printf("\td1s1\t\td2s1\n\n");
  1410. X    printf("Choose the type your students can best remember.\n");
  1411. X    printf("\nEnter the sections of your course one per line.\n");
  1412. X    printf("Use a dot (`.\') on a line by itself to stop.\n");
  1413. X    div = 1;
  1414. X    sec = 1;
  1415. X    cnt = 0;
  1416. X    pcComma = pcSections;
  1417. X    for (;;) {
  1418. X        if ((char *)0 == pcComma || '\000' == pcComma) {
  1419. X            sprintf(acTemp, "d%ds%d", div, sec);
  1420. X        } else {
  1421. X            register int i;
  1422. X            for (i = 0; i < MAXDIVSEC; ++i) {
  1423. X                if ('\000' == *pcComma) {
  1424. X                    pcComma = (char *)0;
  1425. X                    break;
  1426. X                }
  1427. X                if (',' == *pcComma) {
  1428. X                    ++pcComma;
  1429. X                    break;
  1430. X                }
  1431. X                acTemp[i] = *pcComma++;
  1432. X            }
  1433. X            acTemp[i] = '\000';
  1434. X        }
  1435. X        printf("section [%s] > ", acTemp);
  1436. X        if ((char *)0 == GetWord(acDiv, MAXDIVSEC, acTemp)) {
  1437. X            fprintf(fpMail, "\n\n!! Aborted !!\n\n");
  1438. X            (fProc ? pclose : fclose)(fpMail);
  1439. X            exit(0);
  1440. X        }
  1441. X        if ('.' == acDiv[0] && '\000' == acDiv[1]) {
  1442. X            if (0 == cnt) {
  1443. X                fprintf(fpMail, "%c%s", SEP,  acSectIgnore);
  1444. X                ++cnt;
  1445. X            }
  1446. X            break;
  1447. X        }
  1448. X        if (BadName(acDiv)) {
  1449. X            printf("Divisions must have alpha-numeric names.\n");
  1450. X            continue;
  1451. X        }
  1452. X        fprintf(fpMail, "%c%s", (0 == cnt ? SEP : ','), acDiv);
  1453. X        ++cnt;
  1454. X
  1455. X        /* make d<div>s<sec> easy to do for Purdue
  1456. X         */
  1457. X        if ('d' == acDiv[0] && isdigit(acDiv[1])) {
  1458. X            register char *pc;
  1459. X            div = atoi(acDiv+1);
  1460. X            if ((char *)0 != (pc = strchr(acDiv+2, 's')) && isdigit(pc[1])) {
  1461. X                sec = atoi(pc+1);
  1462. X            }
  1463. X        }
  1464. X        if (10 == ++sec) {
  1465. X            ++div;
  1466. X            sec = 1;
  1467. X        }
  1468. X    }
  1469. X
  1470. X    printf("\nLastly, if you would like to be notified by phone when this is done\n");
  1471. X    printf("Please enter a phone number now: [No, Thanks] ");
  1472. X    (void) GetWord(acLong, MAXLONGNAME, "[No Phone Call Requested]");
  1473. X
  1474. X    if (0 != strcmp(acDefGroup, acGroup)) {
  1475. X        fprintf(fpMail, "\n(default group was %s)", acDefGroup);
  1476. X    }
  1477. X    fprintf(fpMail, "\n\nPhone: %s\n", acLong);
  1478. X    fprintf(fpMail, "\nPrevious experience: %s", acPrevExp);
  1479. X    fprintf(fpMail, "\nDatabase file: `%s\'", acTurnbase);
  1480. X    if (fFound) {
  1481. X        fprintf(fpMail, "\nPrevious database line:\n\t%s:%s:%s:%s:%s", pcCourse, pcUid, pcDir, pcGroup, pcSections);
  1482. X    }
  1483. X
  1484. X    (fProc ? pclose : fclose)(fpMail); /* works for fopen too, now */
  1485. X
  1486. X    endgrent();
  1487. X
  1488. X    printf("\nMail %s been sent to a superuser to finish the configuration.\n", fExec ? "has" : "would have" );
  1489. X    if (fExec) {
  1490. X        printf("You will be contacted via email or telephone when your account\n");
  1491. X        printf("is ready for use.\n");
  1492. X    }
  1493. X    return fdLock;
  1494. }
  1495. X
  1496. X
  1497. /*
  1498. X * send the sysadmin mail telling her to remove us from the db        (ksb)
  1499. X */
  1500. static void
  1501. DoQuit()
  1502. {
  1503. X    auto char acCmd[MAXPATHLEN+300];
  1504. X    auto int fProc;
  1505. X    auto FILE *fpMail;
  1506. X
  1507. X    sprintf(acCmd, "%s -s \"%s: please delete \\`%s'\" %s", MAILX_PATH, progname, pcCourse, acMailAddr);
  1508. X
  1509. X    if ((FILE *)0 == (fpMail = popen(acCmd, "w"))) {
  1510. X        fprintf(stderr, "%s: cannot open mail cmd (%s).\n", progname, strerror(errno));
  1511. X        if ((FILE *)0 == (fpMail = fopen(acDeadLetter, "a"))) {
  1512. X            exit(1);
  1513. X        }
  1514. X        fprintf(stderr, "%s: holding letter in %s\n", progname, acDeadLetter);
  1515. X        fProc = 0;
  1516. X    } else {
  1517. X        fProc = 1;
  1518. X    }
  1519. X    fprintf(fpMail, "\nPlease remove %s from the project database, `%s\'.\n", pcCourse, acTurnbase);
  1520. X    fprintf(fpMail, "\nThanks.\n");
  1521. X    (fProc ? pclose : fclose)(fpMail);
  1522. X    printf("\nMail %s been sent to a superuser to finish the job.\n", fExec ? "has" : "would have" );
  1523. }
  1524. X
  1525. X
  1526. static char acUsage[] = "[-cdehinqrvV] [-c course] [-G cmd] [-g cmd] [project]";
  1527. static char *apcHelp[] = {    /* a task help message            */
  1528. X    "c course select which course to administer",
  1529. X    "d     allow no submissions for a while",
  1530. X    "e     allow submissions and change default project name",
  1531. X    "l     allow submissions without changing default project",
  1532. X    "G cmd     execute command for each division",
  1533. X    "g cmd     execute command for all submitted files",
  1534. X    "h     print this message",
  1535. X    "i     initialize an account for submissions",
  1536. X    "n     just print what would be done",
  1537. X    "o     display a status line",
  1538. X    "q     quit using this account for submissions",
  1539. X    "r     delete a project",
  1540. X    "v     output shell commands",
  1541. X    "V     output version information",
  1542. X    (char *)0
  1543. };
  1544. static char *apcEsc[] =     {    /* an escape help message        */
  1545. X    "cmd: may include any of %[htpdus%] which will be expanded before execution",
  1546. X    "%h    home directory of instructor",
  1547. X    "%t    turnin directory name",
  1548. X    "%p    current project number",
  1549. X    "%d    division/section identifier",
  1550. X    "%u    current user identifier, or `*\'",
  1551. X    "%s    full path (%h/%t/%p/%d/%u) to tar file",
  1552. X    "%%    a %",
  1553. X    (char *)0
  1554. };
  1555. X
  1556. /*
  1557. X * read turnin data base                        (ksb)
  1558. X * make a guess at the course
  1559. X * which project, on?  default?
  1560. X * make tar file
  1561. X * maybe display it
  1562. X */
  1563. int
  1564. main(argc, argv)
  1565. int argc;
  1566. char **argv;
  1567. {
  1568. X    static int fGiven = 0;
  1569. X    auto char acTop[MAXPATHLEN+1];
  1570. X    auto char acYes[MAXYESNO+1];
  1571. X    auto int i;
  1572. X    auto int iTemp, fdLock;
  1573. X
  1574. X    umask(022);
  1575. X
  1576. X    if ((char *)0 == (progname = strrchr(argv[0], '/')))
  1577. X        progname = argv[0];
  1578. X    else
  1579. X        ++progname;
  1580. X
  1581. X    (void) setpwent();
  1582. X    if (NULL == (ppwMe = getpwuid(getuid()))) {
  1583. X        fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, getuid(), strerror(errno));
  1584. X        exit(99);
  1585. X    }
  1586. X
  1587. X    options(argc, argv);
  1588. X    if (What == INITIALIZE) {
  1589. X        printf("%s: initialize user %s for a course\n", progname, ppwMe->pw_name);
  1590. X        if (-1 == chdir(ppwMe->pw_dir)) {
  1591. X            fprintf(stderr, "%s: chdir: %s: %s\n", progname, ppwMe->pw_dir, strerror(errno));
  1592. X            exit(2);
  1593. X        }
  1594. X        fdLock = DoInit();
  1595. X        iProjnum = 0;
  1596. X        Projstatus[0] = OFF;
  1597. X        newprojects(0);
  1598. X        /* reply mail should include instructions for enabling projects
  1599. X         */
  1600. X        (void) close(fdLock);
  1601. X        exit(0);
  1602. X    }
  1603. X
  1604. X    /* we change ppwMe below to reflect root becoming the user
  1605. X     */
  1606. X    if (NULL == (ppwMe = getpwuid(geteuid()))) {
  1607. X        fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, geteuid(), strerror(errno));
  1608. X        exit(99);
  1609. X    }
  1610. X    if (0 == getcourse(acTurnbase)) {
  1611. X        if ((char *)0 == pcCourse)
  1612. X            fprintf(stderr, "%s: user %s not in database\n", progname, ppwMe->pw_name);
  1613. X        else
  1614. X            fprintf(stderr, "%s: course %s not in database\n", progname, pcCourse);
  1615. X        exit(1);
  1616. X    }
  1617. X    /* if we are root, become Prof here (which might be `lroot')
  1618. X     */
  1619. X    if ((struct passwd *)0 == (ppwMe = getpwnam(pcUid))) {
  1620. X        fprintf(stderr, "%s: getpwname: %s: %s\n", progname, pcUid, strerror(errno));
  1621. X        fprintf(stderr, "%s: no such course here\n", progname);
  1622. X        exit(1);
  1623. X    }
  1624. X    if (-1 == setuid(ppwMe->pw_uid)) {
  1625. X        fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
  1626. X        exit(20);
  1627. X    }
  1628. X
  1629. X    if (0 == geteuid()) {
  1630. X        fprintf(stderr, "%s: run as root [ny]? ", progname);
  1631. X        fflush(stderr);
  1632. X        (void) GetWord(acYes, MAXYESNO, "no");
  1633. X        if ('y' != acYes[0] && 'Y' != acYes[0]) {
  1634. X            fprintf(stderr, "Aborted.\n");
  1635. X            exit(0);
  1636. X        }
  1637. X    }
  1638. X    sprintf(acTop, "%s/%s", ppwMe->pw_dir, pcDir);
  1639. X    ceedee(acTop);
  1640. X
  1641. X    fdLock = OpenLock();
  1642. X
  1643. X    getprojects();
  1644. X
  1645. X    if (EOF != getarg(argc, argv)) {
  1646. X        fGiven = 1;
  1647. X        CheckChars("on the command line", optarg);
  1648. X        iTemp = search(optarg);
  1649. X    } else {
  1650. X        iTemp = iProjnum;
  1651. X    }
  1652. X
  1653. X    if (-1 != iTemp) {
  1654. X        strcpy(acMp, aacProjnames[iTemp]);
  1655. X    }
  1656. X
  1657. X    switch (What) {
  1658. X    case ENABLE:
  1659. X        if (-1 == iTemp) {
  1660. X            fprintf(stderr, "%s: no default project\n", progname);
  1661. X            exit(1);
  1662. X        }
  1663. X        iProjnum = iTemp;
  1664. X        Projstatus[iTemp] = ON;
  1665. X        Make(acMp);
  1666. X        newprojects(1);
  1667. X        break;
  1668. X
  1669. X    case QUIT:
  1670. X        fprintf(stdout, "Are you sure you want to stop using %s [ny]? ", progname);
  1671. X        (void) GetWord(acYes, MAXYESNO, "no");
  1672. X        if ('y' != acYes[0] && 'Y' != acYes[0]) {
  1673. X            fprintf(stdout, "Aborted.\n");
  1674. X            exit(0);
  1675. X        }
  1676. X        for (i = 0; i < iProjcount; ++i) {
  1677. X            if (DELETE == Projstatus[i]) {
  1678. X                continue;
  1679. X            }
  1680. X            strcpy(acMp, aacProjnames[i]);
  1681. X            fprintf(stdout, "%s: remove project %s [ynq] ", progname, acMp);
  1682. X            (void) GetWord(acYes, MAXYESNO, "yes");
  1683. X            if ('q' == acYes[0] || 'Q' == acYes[0]) {
  1684. X                fprintf(stdout, "Aborted.\n");
  1685. X                exit(0);
  1686. X            }
  1687. X            if ('y' != acYes[0] && 'Y' != acYes[0]) {
  1688. X                continue;
  1689. X            }
  1690. X            Remove(aacProjnames[i]);
  1691. X            Projstatus[i] = DELETE;
  1692. X        }
  1693. X        for (i = 0; i < iProjcount; ++i) {
  1694. X            if (DELETE != Projstatus[i]) {
  1695. X                break;
  1696. X            }
  1697. X        }
  1698. X        if (i != iProjcount) {
  1699. X            printf("%s: not all projects removed, quit.\n", progname);
  1700. X            newprojects(1);
  1701. X            break;
  1702. X        }
  1703. X        ceedee("..");
  1704. X        if (fExec) {
  1705. X            DoQuit();
  1706. X        }
  1707. X        rm(pcDir);
  1708. X        break;
  1709. X
  1710. X    case REMOVE:
  1711. X        if (-1 == iTemp) {
  1712. X            fprintf(stderr, "%s: no default project\n", progname);
  1713. X            exit(1);
  1714. X        }
  1715. X        fprintf(stdout, "Are you sure you want to delete all submissions for project %s [ny]? ", acMp);
  1716. X        (void) GetWord(acYes, MAXYESNO, "no");
  1717. X        if ('y' != acYes[0] && 'Y' != acYes[0]) {
  1718. X            fprintf(stdout, "Aborted.\n");
  1719. X            exit(0);
  1720. X        }
  1721. X        Remove(acMp);
  1722. X        Projstatus[iTemp] = DELETE;
  1723. X        newprojects(1);
  1724. X        break;
  1725. X
  1726. X    case DISABLE:
  1727. X        if (-1 == iTemp) {
  1728. X            fprintf(stderr, "%s: no default project\n", progname);
  1729. X            exit(1);
  1730. X        }
  1731. X        Projstatus[iTemp] = OFF;
  1732. X        newprojects(1);
  1733. X        break;
  1734. X
  1735. X    case GRADE:
  1736. X        if (-1 == iTemp) {
  1737. X            fprintf(stderr, "%s: no default project\n", progname);
  1738. X            exit(1);
  1739. X        }
  1740. #if HAVE_NICE
  1741. X        nice(2);
  1742. #else /* vax */
  1743. X        setpriority(PRIO_PROCESS, getpid(), 2);
  1744. #endif /* machine */
  1745. X        scan();
  1746. X        break;
  1747. X
  1748. X    case OUTPUT:
  1749. X        fprintf(stdout, "%s: user: %s.%s, course: %s, subdirectory: %s\n", progname, ppwMe->pw_name, pcGroup, pcCourse, pcDir);
  1750. X        for (i = 0; i < iProjcount; ++i) {
  1751. X            fprintf(stdout, "%s: project %-8s (%s)\n", progname, aacProjnames[i], (OFF == Projstatus[i] ? "off" : iProjnum == i ? "default" : "on"));
  1752. X        }
  1753. X        break;
  1754. X
  1755. X    case VERSION:
  1756. X        printf("%s: %s\n", progname, RCSId);
  1757. X        printf("%s: default directory name: %s\n", progname, acSubmit);
  1758. X        break;
  1759. X
  1760. X    case LATE:
  1761. X        if (-1 == iTemp) {
  1762. X            fprintf(stderr, "%s: no default project\n", progname);
  1763. X            exit(1);
  1764. X        }
  1765. X        if (iTemp == iProjnum) {
  1766. X            iProjnum = -1;
  1767. X        }
  1768. X        Projstatus[iTemp] = ON;
  1769. X        Make(acMp);
  1770. X        newprojects(1);
  1771. X        break;
  1772. X
  1773. X    case HELP:
  1774. X        fprintf(stdout, "%s: usage %s\n", progname, acUsage);
  1775. X        for (i = 0; apcHelp[i]; ++i) {
  1776. X            fprintf(stdout, "%s\n", apcHelp[i]);
  1777. X        }
  1778. X        if (fVerbose) {
  1779. X            for (i = 0; apcEsc[i]; ++i) {
  1780. X                fprintf(stdout, "%s\n", apcEsc[i]);
  1781. X            }
  1782. X        }
  1783. X        break;
  1784. X
  1785. X    case UNKNOWN:
  1786. X        if (fGiven) {
  1787. X            Make(acMp);
  1788. X            newprojects(1);
  1789. X            break;
  1790. X        }
  1791. X        /*fallthrough*/
  1792. X    default:
  1793. X        fprintf(stderr, "%s: usage %s\n", progname, acUsage);
  1794. X        break;
  1795. X    }
  1796. X
  1797. X    (void) endpwent();
  1798. X    (void) close(fdLock);
  1799. X    exit(0);
  1800. }
  1801. Purdue
  1802. chmod 0444 project/project.c ||
  1803. echo 'restore of project/project.c failed'
  1804. Wc_c="`wc -c < 'project/project.c'`"
  1805. test 32572 -eq "$Wc_c" ||
  1806.     echo 'project/project.c: original size 32572, current size' "$Wc_c"
  1807. fi
  1808. exit 0
  1809.  
  1810. exit 0 # Just in case...
  1811.